//------------------------------------------------------------------------------
// <copyright file="OleDbConnection.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------

namespace System.Data.OleDb {

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Data.Common;
    using System.Data.ProviderBase;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Permissions;
    using System.Text;
    using System.Threading;
    using SysTx = System.Transactions;

    // wraps the OLEDB IDBInitialize interface which represents a connection
    // Notes about connection pooling
    // 1. Connection pooling isn't supported on Win95
    // 2. Only happens if we use the IDataInitialize or IDBPromptInitialize interfaces
    //    it won't happen if you directly create the provider and set its properties
    // 3. First call on IDBInitialize must be Initialize, can't QI for any other interfaces before that
    [DefaultEvent("InfoMessage")]
    public sealed partial class OleDbConnection : DbConnection, ICloneable, IDbConnection { 

        static private readonly object EventInfoMessage = new object();

        public OleDbConnection(string connectionString) : this() {
            ConnectionString = connectionString;
        }

        private OleDbConnection(OleDbConnection connection) : this() { // Clone
            CopyFrom(connection);
        }

        [
        DefaultValue(""),
#pragma warning disable 618 // ignore obsolete warning about RecommendedAsConfigurable to use SettingsBindableAttribute
        RecommendedAsConfigurable(true),
#pragma warning restore 618
        SettingsBindableAttribute(true),
        RefreshProperties(RefreshProperties.All),
        ResCategoryAttribute(Res.DataCategory_Data),
        Editor("Microsoft.VSDesigner.Data.ADO.Design.OleDbConnectionStringEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
        ResDescriptionAttribute(Res.OleDbConnection_ConnectionString),
        ]
        override public string ConnectionString {
            get {
                return ConnectionString_Get();
            }
            set {
                ConnectionString_Set(value);
            }
        }

        private OleDbConnectionString OleDbConnectionStringValue {
            get { return (OleDbConnectionString)ConnectionOptions; }
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ResDescriptionAttribute(Res.OleDbConnection_ConnectionTimeout),
        ]
        override public int ConnectionTimeout {
            get {
                IntPtr hscp;
                Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.get_ConnectionTimeout|API> %d#\n", ObjectID);
                try {
                    object value = null;
                    if (IsOpen) {
                        value = GetDataSourceValue(OleDbPropertySetGuid.DBInit, ODB.DBPROP_INIT_TIMEOUT);
                    }
                    else {
                        OleDbConnectionString constr = this.OleDbConnectionStringValue;
                        value = (null != constr) ? constr.ConnectTimeout : ADP.DefaultConnectionTimeout;
                    }
                    if (null != value) {
                        return Convert.ToInt32(value, CultureInfo.InvariantCulture);
                    }
                    else {
                        return ADP.DefaultConnectionTimeout;
                    }
                }
                finally {
                    Bid.ScopeLeave(ref hscp);
                }
            }
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ResDescriptionAttribute(Res.OleDbConnection_Database),
        ]
        override public string Database {
            get {
                IntPtr hscp;
                Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.get_Database|API> %d#\n", ObjectID);
                try {
                    OleDbConnectionString constr = (OleDbConnectionString)UserConnectionOptions;
                    object value = (null != constr) ? constr.InitialCatalog : ADP.StrEmpty;
                    if ((null != value) && !((string)value).StartsWith(DbConnectionOptions.DataDirectory, StringComparison.OrdinalIgnoreCase)) {
                        OleDbConnectionInternal connection = GetOpenConnection();
                        if (null != connection) {
                            if (connection.HasSession) {
                                value = GetDataSourceValue(OleDbPropertySetGuid.DataSource, ODB.DBPROP_CURRENTCATALOG);
                            }
                            else {
                                value = GetDataSourceValue(OleDbPropertySetGuid.DBInit, ODB.DBPROP_INIT_CATALOG);
                            }
                        }
                        else {
                            constr = this.OleDbConnectionStringValue;
                            value = (null != constr) ? constr.InitialCatalog : ADP.StrEmpty;
                        }
                    }
                    return Convert.ToString(value, CultureInfo.InvariantCulture);
                }
                finally {
                    Bid.ScopeLeave(ref hscp);
                }
            }
        }

        [
        Browsable(true),
        ResDescriptionAttribute(Res.OleDbConnection_DataSource),
        ]
        override public string DataSource {
            get {
                IntPtr hscp;
                Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.get_DataSource|API> %d#\n", ObjectID);
                try {
                    OleDbConnectionString constr = (OleDbConnectionString)UserConnectionOptions;
                    object value = (null != constr) ? constr.DataSource : ADP.StrEmpty;
                    if ((null != value) && !((string)value).StartsWith(DbConnectionOptions.DataDirectory, StringComparison.OrdinalIgnoreCase)) {
                        if (IsOpen) {
                            value = GetDataSourceValue(OleDbPropertySetGuid.DBInit, ODB.DBPROP_INIT_DATASOURCE);
                            if ((null == value) || ((value is string) && (0 == (value as string).Length))) {
                                value = GetDataSourceValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_DATASOURCENAME); // MDAC 76248
                            }
                        }
                        else {
                            constr = this.OleDbConnectionStringValue;
                            value = (null != constr) ? constr.DataSource : ADP.StrEmpty;
                        }
                    }
                    return Convert.ToString(value, CultureInfo.InvariantCulture);
                }
                finally {
                    Bid.ScopeLeave(ref hscp);
                }
            }
        }

        internal bool IsOpen {
            get { return (null != GetOpenConnection()); }
        }

        internal OleDbTransaction LocalTransaction {
            set {
                OleDbConnectionInternal openConnection = GetOpenConnection();

                if (null != openConnection) {
                    openConnection.LocalTransaction = value;
                }
            }
        }

        [
        Browsable(true),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
       ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.OleDbConnection_Provider),
        ]
        public String Provider {
            get {
                Bid.Trace("<oledb.OleDbConnection.get_Provider|API> %d#\n", ObjectID);
                OleDbConnectionString constr = this.OleDbConnectionStringValue;
                string value = ((null != constr) ? constr.ConvertValueToString(ODB.Provider, null) : null);
                return ((null != value) ? value : ADP.StrEmpty);
            }
        }
        
        internal OleDbConnectionPoolGroupProviderInfo ProviderInfo {
            get {
                return (OleDbConnectionPoolGroupProviderInfo)PoolGroup.ProviderInfo;
            }
        }

        [
        ResDescriptionAttribute(Res.OleDbConnection_ServerVersion),
        ]
        override public string ServerVersion { // MDAC 55481
            get {
                return InnerConnection.ServerVersion;
            }
        }

        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ResDescriptionAttribute(Res.DbConnection_State),
        ]
        override public ConnectionState State {
            get {
                return InnerConnection.State;
            }
        }

        [
        EditorBrowsableAttribute(EditorBrowsableState.Advanced),
        ]
        public void ResetState() { // MDAC 58606
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, "<oledb.OleDbCommand.ResetState|API> %d#\n", ObjectID);
            try {
                if (IsOpen) {
                    object value = GetDataSourcePropertyValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_CONNECTIONSTATUS);
                    if (value is Int32) {
                        int connectionStatus = (int) value;
                        switch (connectionStatus) {
                        case ODB.DBPROPVAL_CS_UNINITIALIZED: // provider closed on us
                        case ODB.DBPROPVAL_CS_COMMUNICATIONFAILURE: // broken connection
                            GetOpenConnection().DoomThisConnection();
                            NotifyWeakReference(OleDbReferenceCollection.Canceling); // MDAC 71435
                            Close();
                            break;

                        case ODB.DBPROPVAL_CS_INITIALIZED: // everything is okay
                            break;

                        default: // have to assume everything is okay
                            Debug.Assert(false, "Unknown 'Connection Status' value " + connectionStatus.ToString("G", CultureInfo.InvariantCulture));
                            break;
                        }
                    }
                }
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        }

        [
        ResCategoryAttribute(Res.DataCategory_InfoMessage),
        ResDescriptionAttribute(Res.DbConnection_InfoMessage),
        ]
        public event OleDbInfoMessageEventHandler InfoMessage {
            add {
                Events.AddHandler(EventInfoMessage, value);
            }
            remove {
                Events.RemoveHandler(EventInfoMessage, value);
            }
        }

        internal UnsafeNativeMethods.ICommandText ICommandText() {
            Debug.Assert(null != GetOpenConnection(), "ICommandText closed");
            return GetOpenConnection().ICommandText();
        }

        private IDBPropertiesWrapper IDBProperties() {
            Debug.Assert(null != GetOpenConnection(), "IDBProperties closed");
            return GetOpenConnection().IDBProperties();
        }

        internal IOpenRowsetWrapper IOpenRowset() {
            Debug.Assert(null != GetOpenConnection(), "IOpenRowset closed");
            return GetOpenConnection().IOpenRowset();
        }

        internal int SqlSupport() {
            Debug.Assert(null != this.OleDbConnectionStringValue, "no OleDbConnectionString SqlSupport");
            return this.OleDbConnectionStringValue.GetSqlSupport(this);
        }

        internal bool SupportMultipleResults() {
            Debug.Assert(null != this.OleDbConnectionStringValue, "no OleDbConnectionString SupportMultipleResults");
            return this.OleDbConnectionStringValue.GetSupportMultipleResults(this);
        }

        internal bool SupportIRow(OleDbCommand cmd) { // MDAC 72902
            Debug.Assert(null != this.OleDbConnectionStringValue, "no OleDbConnectionString SupportIRow");
            return this.OleDbConnectionStringValue.GetSupportIRow(this, cmd);
        }

        internal int QuotedIdentifierCase() { // MDAC 67385
            Debug.Assert(null != this.OleDbConnectionStringValue, "no OleDbConnectionString QuotedIdentifierCase");
            
            int quotedIdentifierCase;
            object value = GetDataSourcePropertyValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_QUOTEDIDENTIFIERCASE);
            if (value is Int32) {// not OleDbPropertyStatus
                quotedIdentifierCase =  (int) value;
            }
            else {
                quotedIdentifierCase = -1;
            }
            return quotedIdentifierCase;
        }

        new public OleDbTransaction BeginTransaction() {
            return BeginTransaction(IsolationLevel.Unspecified);
        }

        new public OleDbTransaction BeginTransaction(IsolationLevel isolationLevel) {
            return (OleDbTransaction)InnerConnection.BeginTransaction(isolationLevel);
        }

        override public void ChangeDatabase(string value) {
            OleDbConnection.ExecutePermission.Demand();

            IntPtr hscp;
            Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.ChangeDatabase|API> %d#, value='%ls'\n", ObjectID, value);
            try {
                CheckStateOpen(ADP.ChangeDatabase);
                if ((null == value) || (0 == value.Trim().Length)) { // MDAC 62679
                    throw ADP.EmptyDatabaseName();
                }
                SetDataSourcePropertyValue(OleDbPropertySetGuid.DataSource, ODB.DBPROP_CURRENTCATALOG, ODB.Current_Catalog, true, value);
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        }

        internal void CheckStateOpen(string method) {
            ConnectionState state = State;
            if (ConnectionState.Open != state) {
                throw ADP.OpenConnectionRequired(method, state);
            }
        }

        object ICloneable.Clone() {
            OleDbConnection clone = new OleDbConnection(this);
            Bid.Trace("<oledb.OleDbConnection.Clone|API> %d#, clone=%d#\n", ObjectID, clone.ObjectID);
            return clone;
        }

        override public void Close() {
            InnerConnection.CloseConnection(this, ConnectionFactory);
            // does not require GC.KeepAlive(this) because of OnStateChange
        }

        new public OleDbCommand CreateCommand() {
            return new OleDbCommand("", this);
        }

        private void DisposeMe(bool disposing) { // MDAC 65459
            if (disposing) { // release mananged objects
                if (DesignMode) {
                    // release the object pool in design-mode so that
                    // native MDAC can be properly released during shutdown
                    OleDbConnection.ReleaseObjectPool();
                }
            }
        }


        // suppress this message - we cannot use SafeHandle here. Also, see notes in the code (VSTFDEVDIV# 560355)
        [SuppressMessage("Microsoft.Reliability", "CA2004:RemoveCallsToGCKeepAlive")]
        override protected DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) {
            IntPtr hscp;

            Bid.ScopeEnter(out hscp, "<prov.OleDbConnection.BeginDbTransaction|API> %d#, isolationLevel=%d{ds.IsolationLevel}", ObjectID, (int)isolationLevel);
            try {

                DbTransaction transaction = InnerConnection.BeginTransaction(isolationLevel);

                // VSTFDEVDIV# 560355 - InnerConnection doesn't maintain a ref on the outer connection (this) and 
                //   subsequently leaves open the possibility that the outer connection could be GC'ed before the DbTransaction
                //   is fully hooked up (leaving a DbTransaction with a null connection property). Ensure that this is reachable
                //   until the completion of BeginTransaction with KeepAlive
                GC.KeepAlive(this);

                return transaction;
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        }

        public void EnlistDistributedTransaction(System.EnterpriseServices.ITransaction transaction) {
            EnlistDistributedTransactionHelper(transaction);
        }

        internal object GetDataSourcePropertyValue(Guid propertySet, int propertyID) {
            OleDbConnectionInternal connection = GetOpenConnection();
            return connection.GetDataSourcePropertyValue(propertySet, propertyID);
        }

        internal object GetDataSourceValue(Guid propertySet, int propertyID) {
            object value = GetDataSourcePropertyValue(propertySet, propertyID);
            if ((value is OleDbPropertyStatus) || Convert.IsDBNull(value)) {
                value = null;
            }
            return value;
        }

        private OleDbConnectionInternal GetOpenConnection() {
            DbConnectionInternal innerConnection = InnerConnection;
            return (innerConnection as OleDbConnectionInternal);
        }

        internal void GetLiteralQuotes(string method, out string quotePrefix, out string quoteSuffix) {
            CheckStateOpen(method);
            OleDbConnectionPoolGroupProviderInfo info = ProviderInfo;
            if (info.HasQuoteFix) {
                quotePrefix = info.QuotePrefix;
                quoteSuffix = info.QuoteSuffix;
            }
            else {
                OleDbConnectionInternal connection = GetOpenConnection();
                quotePrefix = connection.GetLiteralInfo(ODB.DBLITERAL_QUOTE_PREFIX);
                quoteSuffix = connection.GetLiteralInfo(ODB.DBLITERAL_QUOTE_SUFFIX);
                if (null == quotePrefix) {
                    quotePrefix = "";
                }
                if (null == quoteSuffix) {
                    quoteSuffix = quotePrefix;
                }
                info.SetQuoteFix(quotePrefix, quoteSuffix);
            }
        }

        public DataTable GetOleDbSchemaTable(Guid schema, object[] restrictions) { // MDAC 61846
            OleDbConnection.ExecutePermission.Demand();
            
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.GetOleDbSchemaTable|API> %d#, schema=%ls, restrictions\n", ObjectID, schema);
            try {
                CheckStateOpen(ADP.GetOleDbSchemaTable);
                OleDbConnectionInternal connection = GetOpenConnection();

                if (OleDbSchemaGuid.DbInfoLiterals == schema) {
                    if ((null == restrictions) || (0 == restrictions.Length)) {
                        return connection.BuildInfoLiterals();
                    }
                    throw ODB.InvalidRestrictionsDbInfoLiteral("restrictions");
                }
                else if (OleDbSchemaGuid.SchemaGuids == schema) {
                    if ((null == restrictions) || (0 == restrictions.Length)) {
                        return connection.BuildSchemaGuids();
                    }
                    throw ODB.InvalidRestrictionsSchemaGuids("restrictions");
                }
                else if (OleDbSchemaGuid.DbInfoKeywords == schema) {
                    if ((null == restrictions) || (0 == restrictions.Length)) {
                        return connection.BuildInfoKeywords();
                    }
                    throw ODB.InvalidRestrictionsDbInfoKeywords("restrictions");
                }

                if (connection.SupportSchemaRowset(schema)) {
                    return connection.GetSchemaRowset(schema, restrictions);
                }
                else {
                    using(IDBSchemaRowsetWrapper wrapper = connection.IDBSchemaRowset()) {
                        if (null == wrapper.Value) {
                            throw ODB.SchemaRowsetsNotSupported(Provider); // MDAC 72689
                        }
                    }
                    throw ODB.NotSupportedSchemaTable(schema, this); // MDAC 63279
                }
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        }

        internal DataTable GetSchemaRowset(Guid schema, object[] restrictions) {
            Debug.Assert(null != GetOpenConnection(), "GetSchemaRowset closed");
            return GetOpenConnection().GetSchemaRowset(schema, restrictions);
        }

        internal bool HasLiveReader(OleDbCommand cmd)  {
            bool result = false;
            OleDbConnectionInternal openConnection = GetOpenConnection();

            if (null != openConnection) {
                result = openConnection.HasLiveReader(cmd);
            }
            return result;
        }

        internal void OnInfoMessage(UnsafeNativeMethods.IErrorInfo errorInfo, OleDbHResult errorCode) {
            OleDbInfoMessageEventHandler handler = (OleDbInfoMessageEventHandler) Events[EventInfoMessage];
            if (null != handler) {
                try {
                    OleDbException exception = OleDbException.CreateException(errorInfo, errorCode, null);
                    OleDbInfoMessageEventArgs e = new OleDbInfoMessageEventArgs(exception);
                    if (Bid.TraceOn) {
                        Bid.Trace("<oledb.OledbConnection.OnInfoMessage|API|INFO> %d#, Message='%ls'\n", ObjectID, e.Message);
                    }
                    handler(this, e);
                }
                catch (Exception e) { // eat the exception
                    // 
                    if (!ADP.IsCatchableOrSecurityExceptionType(e)) {
                        throw;
                    }

                    ADP.TraceExceptionWithoutRethrow(e);
                }
            }
#if DEBUG
            else {
                OleDbException exception = OleDbException.CreateException(errorInfo, errorCode, null);
                Bid.Trace("<oledb.OledbConnection.OnInfoMessage|API|INFO> %d#, Message='%ls'\n", ObjectID, exception.Message);
            }
#endif
        }
        
        override public void Open() {
            InnerConnection.OpenConnection(this, ConnectionFactory);
            
            // SQLBUDT #276132 - need to manually enlist in some cases, because
            // native OLE DB doesn't know about SysTx transactions.
            if ((0!=(ODB.DBPROPVAL_OS_TXNENLISTMENT & ((OleDbConnectionString)(this.ConnectionOptions)).OleDbServices)) 
                        && ADP.NeedManualEnlistment()) {
                GetOpenConnection().EnlistTransactionInternal(SysTx.Transaction.Current);
            }
        }

        internal void SetDataSourcePropertyValue(Guid propertySet, int propertyID, string description, bool required, object value) {
            CheckStateOpen(ADP.SetProperties);
            OleDbHResult hr;
            using(IDBPropertiesWrapper idbProperties = IDBProperties()) {
                using(DBPropSet propSet = DBPropSet.CreateProperty(propertySet, propertyID, required, value)) {
                    
                    Bid.Trace("<oledb.IDBProperties.SetProperties|API|OLEDB> %d#\n", ObjectID);
                    hr = idbProperties.Value.SetProperties(propSet.PropertySetCount, propSet);
                    Bid.Trace("<oledb.IDBProperties.SetProperties|API|OLEDB|RET> %08X{HRESULT}\n", hr);
                    
                    if (hr < 0) {
                        Exception e = OleDbConnection.ProcessResults(hr, null, this);
                        if (OleDbHResult.DB_E_ERRORSOCCURRED == hr) {

                            StringBuilder builder = new StringBuilder();
                            Debug.Assert(1 == propSet.PropertySetCount, "too many PropertySets");

                            tagDBPROP[] dbprops = propSet.GetPropertySet(0, out propertySet);
                            Debug.Assert(1 == dbprops.Length, "too many Properties");

                            ODB.PropsetSetFailure(builder, description, dbprops[0].dwStatus);

                            e = ODB.PropsetSetFailure(builder.ToString(), e);
                        }
                        if (null != e) {
                            throw e;
                        }
                    }
                    else {
                        SafeNativeMethods.Wrapper.ClearErrorInfo();
                    }
                }
            }
        }

        internal bool SupportSchemaRowset(Guid schema) {
            return GetOpenConnection().SupportSchemaRowset(schema);
        }

        internal OleDbTransaction ValidateTransaction(OleDbTransaction transaction, string method) {
            return GetOpenConnection().ValidateTransaction(transaction, method);
        }

        static internal Exception ProcessResults(OleDbHResult hresult, OleDbConnection connection, object src) {
            if ((0 <= (int)hresult) && ((null == connection) || (null == connection.Events[EventInfoMessage]))) {
                SafeNativeMethods.Wrapper.ClearErrorInfo();
                return null;
            }

            // ErrorInfo object is to be checked regardless the hresult returned by the function called
            Exception e = null;
            UnsafeNativeMethods.IErrorInfo errorInfo = null;
            OleDbHResult hr = UnsafeNativeMethods.GetErrorInfo(0, out errorInfo);  // 0 - IErrorInfo exists, 1 - no IErrorInfo
            if ((OleDbHResult.S_OK == hr) && (null != errorInfo)) {
                if (hresult < 0) {
                    // 





                    e = OleDbException.CreateException(errorInfo, hresult, null);
                    //}

                    if (OleDbHResult.DB_E_OBJECTOPEN == hresult) {
                        e = ADP.OpenReaderExists(e);
                    }

                    ResetState(connection);
                }
                else if (null != connection) {
                    connection.OnInfoMessage(errorInfo, hresult);
                }
                else {
                    Bid.Trace("<oledb.OledbConnection|WARN|INFO> ErrorInfo available, but not connection %08X{HRESULT}\n", hresult);
                }
                Marshal.ReleaseComObject(errorInfo);
            }
            else if (0 < hresult) {
                // @devnote: OnInfoMessage with no ErrorInfo
                Bid.Trace("<oledb.OledbConnection|ERR|INFO> ErrorInfo not available %08X{HRESULT}\n", hresult);
            }
            else if ((int)hresult < 0) {
                e = ODB.NoErrorInformation((null != connection) ? connection.Provider : null, hresult, null); // OleDbException

                ResetState(connection);
            }
            if (null != e) {
                ADP.TraceExceptionAsReturnValue(e);
            }
            return e;
        }

        // @devnote: should be multithread safe
        static public void ReleaseObjectPool() {
            (new OleDbPermission(PermissionState.Unrestricted)).Demand();

            IntPtr hscp;
            Bid.ScopeEnter(out hscp, "<oledb.OleDbConnection.ReleaseObjectPool|API>\n");
            try {
                OleDbConnectionString.ReleaseObjectPool();
                OleDbConnectionInternal.ReleaseObjectPool();
                OleDbConnectionFactory.SingletonInstance.ClearAllPools();
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        }

        static private void ResetState(OleDbConnection connection) {
            if (null != connection) {
                connection.ResetState();
            }
        }
    }
}
